#!/usr/bin/env bash

source ../../lib/shell/env.sh
source ../../lib/shell/common.sh

function clean() {
    echo "clean $MEM_LOG"
    [ -f $MEM_LOG ] && rm -rf $MEM_LOG || :
    echo "clean $MEM_STATE"
    [ -f $MEM_STATE ] && rm -rf $MEM_STATE ||:

    for _ in `seq 6`;do
        if pgrep memtester >/dev/null 2>&1;then
            echo "kill memtester"
            kill -9 `pgrep memtester`
            sleep 10
        fi
    done
}

function monitor_mem_used() {
    local monitor_time=$1
    local cur_mem_used=""
    local mem_used_log=""

    #monitor memory used
    echo "monitor memory used--->${monitor_time}s [Time consuming: $(($RUNTIME -10))s]" >>$MEM_STATE

    CUR_USED_MEM=$(sar -r 1 $(($RUNTIME -10))|awk '/Average/{print $4}')
    cur_mem_used=$(echo "scale=2;($CUR_USED_MEM - $START_USED_MEM)/1000"|bc)
    if [ $(echo "scale=2;($MEM_SIZE_MB-2) <= $cur_mem_used"|bc) -eq 1 ] &&
       [ $(echo "scale=2;($MEM_SIZE_MB+2) > $cur_mem_used"|bc) -eq 1 ];then
        mem_used_log="${mem_used_log}cur usage ${cur_mem_used}M, Memory usage(in ${MEM_SIZE_MB}+-2 M) is normal.\n"
    else
        mem_used_log="${mem_used_log}cur usage ${cur_mem_used}M, Memory usage(not in ${MEM_SIZE_MB}+-2 M) is abnormal!.\n"
    fi
    echo -e "$mem_used_log" >> $MEM_STATE
}

function check_memtest_results() {
    local cmd=""
    local failed_msg=""

    while read line;do
        cmd="grep $line $MEM_LOG"
        if eval $cmd;then
            cmd="${cmd} |awk -F: '{print \$NF}'|grep -wq ok"
            if ! eval $cmd;then
                failed_msg="${failed_msg}${line}!\n"
            fi
        else
            failed_msg="${failed_msg}${line} test shouldn't SKIP!\n"
        fi
    done << EOF
    "Stuck Address"
    "Random Value"
    "Compare XOR"
    "Compare SUB"
    "Compare MUL"
    "Compare DIV"
    "Compare OR"
    "Compare AND"
    "Sequential Increment"
    "Solid Bits"
    "Block Sequential"
    "Checkerboard"
    "Bit Spread"
    "Bit Flip"
    "Walking Ones"
    "Walking Zeroes"
    "8-bit Writes"
    "16-bit Writes"
EOF
    [ -n "$failed_msg" ] && { echo -e "$failed_msg";return 1; } || return 0
}

function mem_test_runtime_to_request_mem() {
    #get 80% free memory
    local free_mem=$(free -m|grep -iw Mem|awk '{print $4}')
    local use_free_mem=$(echo "$free_mem * 0.8"|bc)

    check_cmd "memtester"
    echo "==========[memory test Time consuming ${RUNTIME}s]=========="

    #Memory stress test at least 900 seconds
    if [ $(echo "$RUNTIME >= 900"|bc) -eq 0 ];then
        echo "Error: memory stress test need runtime Greater than or equal to 900s, but Current runtime is ${RUNTIME}s" && exit 1
    fi

    #Request memory based on runtime
    if test X"$(arch)" == X"x86_64";then
        MEM_SIZE_MB=$(echo "$RUNTIME * 1000 / 360" | bc)
    else
        MEM_SIZE_MB=$(echo "$RUNTIME * 1000 / 440" | bc)
    fi
    MEM_SIZE_MB=$(echo $MEM_SIZE_MB|sed -e "s,\..*,,g")

    if [ $(echo "$(echo "$MEM_SIZE_MB / 0.8"|bc) > $use_free_mem"|bc) -eq 1 ];then
        echo "warning: request memory $(echo "$MEM_SIZE_MB / 0.8"|bc)M, but host maximum 80% free memory is ${use_free_mem}M, so, Test against real memory until ${RUNTIME}s."
    fi
    echo "==========[request memory ${MEM_SIZE_MB}M, host maximum 80% free memory is ${use_free_mem}M ,when runtime is ${RUNTIME}s]=========="
}

function mem_test() {
    local cur_time=0
    local cur_time_diff=0
    local fail_msg=""

    #Request memory by runtime
    mem_test_runtime_to_request_mem

    #start memtester
    START_USED_MEM=$(sar -r 1 5|awk '/Average/{print $4}')
    echo "memory usage $(echo "scale=2;$START_USED_MEM / 1000"|bc)M before memory test"
    echo "==========[memory test runtime ${RUNTIME}s]=========="
    for ((i=1;i<=$RUNTIME;i+=$cur_time_diff));do
        cur_time="$(date +%s -d "$(date +"%a %b %e %T %Y")")"
        echo -e "[memory test--->${i}s]"
        memtester ${MEM_SIZE_MB}M 1 > $MEM_LOG  &
        sleep 5
        monitor_mem_used $i &
        wait
        cur_time_diff=$(($(date +%s -d "$(date +"%a %b %e %T %Y")") - $cur_time))
        [ $(($i + 2 * $cur_time_diff)) -gt $RUNTIME ] && break
    done

    echo "==========[monitor memory used log]=========="
    cat $MEM_STATE
    echo "==========[monitor memory used log]=========="

    echo -e "\n==========[memtester log]=========="
    cat $MEM_LOG
    echo "==========[memtester log]=========="

    if grep -wq "abnormal" $MEM_STATE;then
        if ! check_memtest_results >/dev/null 2>&1;then
            test_fail
        else
            echo "warning: Abnormal memory usage,During the memtest"
        fi
    else
        check_memtest_results >/dev/null 2>&1 && test_pass || test_fail
    fi
}

trap "clean" EXIT
# # # # # # # # # # # # # # main # # # # # # # # # # # #
stress_memory_env

mem_test && test_pass || test_fail
